package com.stars.easyms.base.bean;

import com.stars.easyms.base.util.ApplicationContextHolder;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * <p>className: LazyLoadBean</p>
 * <p>description: 懒加载bean</p>
 *
 * @author guoguifang
 * @version 1.7.1
 * @date 2020/12/22 10:02 上午
 */
public class LazyLoadBean<T> {

    private Class<T> beanClass;

    private Supplier<T> defaultBeanSupplier;

    private T bean;

    private boolean loaded;

    public LazyLoadBean(@NonNull Class<T> beanClass) {
        this.beanClass = beanClass;
    }

    public LazyLoadBean(@NonNull Supplier<T> defaultBeanSupplier) {
        this.defaultBeanSupplier = defaultBeanSupplier;
    }

    public LazyLoadBean(@NonNull Class<T> beanClass, @NonNull Supplier<T> defaultBeanSupplier) {
        this.beanClass = beanClass;
        this.defaultBeanSupplier = defaultBeanSupplier;
    }

    public void accept(@NonNull Consumer<T> consumer) {
        T localBean = getBean();
        notNull(localBean);
        consumer.accept(localBean);
    }

    public void acceptIfBeanExist(@NonNull Consumer<T> consumer) {
        T localBean = getBean();
        if (localBean != null) {
            consumer.accept(localBean);
        }
    }

    public <R> R apply(@NonNull Function<T, R> function) {
        T localBean = getBean();
        notNull(localBean);
        return function.apply(localBean);
    }

    @NonNull
    public T getNonNullBean() {
        T localBean = getBean();
        notNull(localBean);
        return localBean;
    }

    @Nullable
    public synchronized T getBean() {
        if (!loaded) {
            if (beanClass != null) {
                bean = ApplicationContextHolder.getBean(beanClass);
            }
            if (bean == null && defaultBeanSupplier != null) {
                bean = defaultBeanSupplier.get();
            }
            loaded = true;
        }
        return bean;
    }

    private void notNull(T localBean) {
        if (localBean == null) {
            if (beanClass != null) {
                throw new IllegalStateException("Cant't find bean for class '" + beanClass.getName() + "'!");
            }
            throw new IllegalStateException("bean is null!");
        }
    }
}
